#!/usr/bin/env python
import configparser
import fnmatch
import os, sys
import time
from argparse import ArgumentParser
import numpy as np
from astropy.io import fits


def _get_value(config, name):
    value = config.get('FITS_HEADER', name)
    if name.upper() in ['H_TRANS', 'V_TRANS', 'IMGINDEX', 'SEQNUM']:
        value = int(value)
    if name.upper() in ['DARKTIME', 'EXPTIME']:
        value = float(value)
    if name.upper() in ['WAVELEN', 'SYSTEMP']:
        value = np.float32(value)
    return value


def readinfo(finfo):
    output = dict()
    cf = configparser.ConfigParser()
    cf.read(finfo)
    if cf.has_section('FITS_HEADER') is False:
        return output
    options = cf.options('FITS_HEADER')
    for opt in options:
        output[opt] = _get_value(cf, opt)
    return output


#def bin2fits(fname, overwrite=False, suffix='bin', nx=1250, ny=4700, dtype='float32'):
#    print('*** bin2fits ***')
#    print('read binary file: {}'.format(fname))
#    if fname.endswith(suffix) is False:
#        print('Error: suffix does not match')
#        return

#    finfo = fname.replace('.{}'.format(suffix), '.info')
#    fout = fname.replace('.{}'.format(suffix), '.fits')

#    if os.path.exists(fout):
#        if overwrite:
#            print('Warning: overwriting existing file')
#        else:
#            print('Error: fits file already exists')
#            return

#    if os.path.exists(finfo):
#        header_info = readinfo(finfo)
#        if len(header_info) == 0:
#            print('Warning: header file does not include FITS_HEADER section')
#        else:
#            print('read header file: {}'.format(finfo))
#    else:
#        header_info = dict()

#    output = np.zeros((ny * 2, nx * 8), dtype=np.uint16)
#    data = np.fromfile(fname, dtype=dtype)
#    if dtype == 'float32':
#        data = data * 4
#    data = data.astype(np.uint16)
#    data = data.reshape((ny * nx, 16))
#    for chan in range(16):
#        y = chan // 8
#        if y == 0:
#            x = chan
#        else:
#            x = 15 - chan
#        x0 = x * nx
#        y0 = y * ny

#        dd = data[:, chan].reshape((ny, nx))
#        if y == 1:
#            dd = dd[::-1, :]
#        if x > 3:
#            dd = dd[:, ::-1]
#        output[y0:y0+ny, x0:x0+nx] = dd

#    hdu = fits.PrimaryHDU(output)
#    for key in header_info:
#        hdu.header[key.upper()] = header_info[key]
#    hdu.writeto(fout, overwrite=overwrite)
#    print('write fits file: {}'.format(fout))


def concat_imgdata(file_root, file_num=47):
    fcnt = 0
    imgdata = None
    while True:
        fname = file_root+'_'+str(fcnt)+'.bin'
        ffname = file_root+'_'+str(fcnt)+'.fake'
        if os.path.isfile(ffname):
            print('load: {}'.format(fname))
            if fcnt == 0:
                imgdata = np.fromfile(fname, dtype=np.uint16)
                start_time = time.perf_counter()
                print('start_time: ', start_time)
            else:
                imgdata = np.concatenate((imgdata,np.fromfile(fname, dtype=np.uint16)))
            fcnt += 1
            
        if fcnt>=file_num:
#            end_time = time.perf_counter()
            break

    return imgdata, start_time
            

def bin2fits(imgdata, fout, overwrite=False, suffix='bin', nx=1250, ny=4700, dtype=np.uint16):
    data = imgdata
    data = data.astype(np.uint16)
    data = data.reshape((ny * nx, 16))
    
    output = np.zeros((ny * 2, nx * 8), dtype=np.uint16)
    for chan in range(16):
        y = chan // 8
        if y == 0:
            x = chan
        else:
            x = 15 - chan
        x0 = x * nx
        y0 = y * ny

        dd = data[:, chan].reshape((ny, nx))
        if y == 1:
            dd = dd[::-1, :]
        if x > 3:
            dd = dd[:, ::-1]
        output[y0:y0+ny, x0:x0+nx] = dd

    hdu = fits.PrimaryHDU(output)
#    for key in header_info:
#        hdu.header[key.upper()] = header_info[key]
    hdu.writeto(fout, overwrite=overwrite)
    print('write fits file: {}'.format(fout))


#def main(path, **kwargs):
#    if os.path.isfile(path):
#        bin2fits(path, **kwargs)

#    elif os.path.isdir(path):
#        if path.endswith('/'):
#            path = path[:-1]
#        pattern = '*.{}'.format(kwargs['suffix'])
#        flist = []
#        for r, d, f in os.walk(path):
#            names = fnmatch.filter(f, pattern)
#            if len(names) > 0:
#                for name in names:
#                    flist.append('{}/{}'.format(r, name))
#        for f in flist:
#            bin2fits(f, **kwargs)

def main():
    imgdata, start_time = concat_imgdata('fk', file_num=47)
    bin2fits(imgdata, 'fk.fits', overwrite=True, suffix='bin', nx=1250, ny=4700, dtype=np.uint16)
    end_time = time.perf_counter()
    os.system('open fk.fits')
    os.system('rm *_*.bin')
    os.system('rm *_*.fake')
    execution_time = end_time - start_time
    print('execution time: {:.6f} seconds'.format(execution_time))
#    print('start_time: ', start_time)
#    print('end_time:   ', end_time)

#if __name__ == '__main__':
#    parser = ArgumentParser()
#    parser.add_argument('path', type=str,
#                        help='file name or directory name (recursively search binary files)')
#    parser.add_argument('--overwrite', '-o', action='store_true',
#                        help='if set, overwrite existing files')
#    parser.add_argument('--suffix', '-s', default='bin', type=str,
#                        help='suffix of binary files, default is "bin"')
#    parser.add_argument('--col', '-x', default=1250, type=int,
#                        help='number of columns in each channel, default is 1250')
#    parser.add_argument('--row', '-y', default=4700, type=int,
#                        help='number of rows in each channel, default is 4700')
#    parser.add_argument('--dtype', '-d', default='uint16', type=str,
#                        help='binary data type, default is uint16')
#    args = parser.parse_args()
#    main(args.path, overwrite=args.overwrite, suffix=args.suffix, nx=args.col, ny=args.row, dtype=args.dtype)
#    main(args.path, overwrite=True, suffix=args.suffix, nx=args.col, ny=args.row, dtype=args.dtype)


if __name__ == '__main__':
    main()
